package com.gitee.huxing;

import com.alibaba.fastjson.JSONObject;
import com.gitee.huxing.course.netty.client.HttpCreateBuilder;
import com.gitee.huxing.course.netty.client.NettyClient;
import com.gitee.huxing.course.netty.listener.NettyListener;
import com.gitee.huxing.course.netty.vo.RequestVO;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Timer;
import java.util.concurrent.*;

/**
 * @Description: netty客户端演示
 * @ProjectName: JavaCourse
 * @Package: com.gitee.huxing.course.netty.client
 * @ClassName: NettyClienDemo
 * @Author: huxing
 * @DateTime: 2021-08-19 下午1:51
 */
@Slf4j
public class NettyClientDemo {

    /** 压力测试一万次，为了方便只给100次了 **/
    private static final int MAX_COUNT = 10000;

    /** netty client启动模式 1: 单例测试, 2: 并发压力测试 默认是1 **/
    public static int loadModule = 1;

    public static void main(String[] args) throws Exception{
        new NettyClientDemo().run();
    }

    public void run() throws Exception{
        Scanner scan = new Scanner(System.in);
        System.out.println("**** netty client测试启动模式 *****");
        System.out.println(" 1: 单客户端验证启动");
        System.out.println(" 2: 并发压力测试启动");
        System.out.println("****************************");
        System.out.print("请选择加载模式: ");
        loadModule = scan.nextInt();
        if (loadModule == 1){
            // 普通单例测试
            new NettyClientDemo().singleNettyClient();
        } else if (loadModule == 2){
            // 并发压力测试
            new NettyClientDemo().threadPoolNettyClient();
        } else {
            // TODO: 这里应该考虑重新接收输入 但是没时间搞 先放这里了
            System.out.println("请选择一个正确的运行模式");
        }
        // 再次唤醒启动模式
        this.run();
    }

    /**
     * @Description: 单例测试
     * @Author: huxing
     * @param
     * @Date: 2021/8/22 下午2:34
     **/
    public void singleNettyClient() throws Exception{
        // 初始化netty客户端
        NettyClient client = new NettyClient("127.0.0.1", 9098);
        // 启动客户端
        try {
            client.start();
        } catch (Exception ex){
            ex.printStackTrace();
            System.out.println("netty客户端启动失败");
        }
        // 获取通信管道
        Channel channel = client.getChannel();
        // 格式化请求
        String body = JSONObject.toJSONString(new RequestVO("Hello, Netty, " +
                "I'm Huxing"));
        // 发送get请求消息
        channel.writeAndFlush(new HttpCreateBuilder().createGetRequest(body,
                "/api/v1/test"));
        // 发送get请求消息
        channel.writeAndFlush(new HttpCreateBuilder().createGetRequest(body,
                "/api/v2/test"));
        // 压力测试执行完成
        System.out.println("========================");
        System.out.println("=======主线程执行完了======");
        System.out.println("========================");
    }

    /**
     * @Description: 线程池压力测试
     * @Author: huxing
     * @param
     * @Date: 2021/8/22 下午2:36
     **/
    private void threadPoolNettyClient() throws Exception{
        // 初始化netty客户端
        NettyClient client = new NettyClient("127.0.0.1", 9098);
        // 启动客户端
        try {
            client.start();
        } catch (Exception ex){
            ex.printStackTrace();
            System.out.println("netty客户端启动失败");
        }
        // 获取通信管道
        Channel channel = client.getChannel();
        // 格式化请求
        ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(2);
        // 定义一个任务线程池
        List<Runnable> tasks = new ArrayList<>();
        for (int i = 0; i < MAX_COUNT; i++){
            tasks.add(new NettyRunnable(i, channel));
        }
        tasks.forEach(threadPoolExecutor::execute);
        // 所有任务执行完成且等待队列中也无任务关闭线程池
        threadPoolExecutor.shutdown();
        // 阻塞主线程, 直至线程池关闭
        threadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        // 压力测试执行完成
        System.out.println("========================");
        System.out.println("=======主线程执行完了======");
        System.out.println("========================");
    }

    static class NettyRunnable implements Runnable{

        /** netty 服务 **/
        private int count;

        private Channel channel;

        public NettyRunnable(int count, Channel channel){
            this.count = count;
            this.channel = channel;
        }

        @Override
        public void run() {
            try {
                // 格式化请求
                String body = JSONObject.toJSONString(new RequestVO("Hello, Netty, " +
                        "I'm Huxing"));
                if (count % 2 == 0){
                    // 发送get请求消息
                    channel.writeAndFlush(new HttpCreateBuilder().createGetRequest(body,
                            "/api/v1/test"));
                } else {
                    // 发送get请求消息
                    channel.writeAndFlush(new HttpCreateBuilder().createGetRequest(body,
                            "/api/v2/test"));
                }
                Thread.sleep(50L);
            } catch (Exception ex){
                log.info("NettyHttp服务(后台)启动失败: {}", ex.getMessage());
            }
        }
    }
}
